﻿#include "CCamerSdkOper.h"
#include <qtextcodec.h>
#include <QRandomGenerator>
#include <QCoreApplication>
#include <QDir>
//#include <gdiplus.h>
#include "CHeader.h"
//#include <Windows.h>
#include <assert.h>
#include <mmsystem.h>
#include <QBuffer>
#include <wingdi.h>

//#pragma comment(lib, "Gdiplus.lib")
//using namespace Gdiplus;




//时间解析宏定义
#define GET_YEAR(_time_)      (((_time_)>>26) + 2000) 
#define GET_MONTH(_time_)     (((_time_)>>22) & 15)
#define GET_DAY(_time_)       (((_time_)>>17) & 31)
#define GET_HOUR(_time_)      (((_time_)>>12) & 31) 
#define GET_MINUTE(_time_)    (((_time_)>>6)  & 63)
#define GET_SECOND(_time_)    (((_time_)>>0)  & 63)

#define ISAPI_OUT_LEN	3 * 1024 * 1024
#define ISAPI_STATUS_LEN  8 * 1024

QMap<LONG, CCamerSdkOper *> g_cCamerOperSdk;
//画温度文字回调 addwxy
void CALLBACK DrawTempText(LONG lRealHandle, HDC hDc, DWORD dwUser)
{
	CCamerSdkOper *pOperCamerSdk = g_cCamerOperSdk[lRealHandle];
	if (nullptr == pOperCamerSdk)
	{
		return;
	}
	pOperCamerSdk->drawTempInfo(lRealHandle, hDc, dwUser);
}

//托辊号回调函数
void CALLBACK DrawRollerNum(LONG lRealHandle, HDC hDc, DWORD dwUser)
{
	CCamerSdkOper *pOperCamerSdk = g_cCamerOperSdk[lRealHandle];
	if (nullptr == pOperCamerSdk)
	{
		return;
	}
	pOperCamerSdk->drawRollerNum(lRealHandle, hDc, dwUser);
}

//跑偏画线和左下角文字回调函数
void CALLBACK DrawCorrectData(LONG lRealHandle, HDC hDc, DWORD dwUser)
{
	CCamerSdkOper *pOperCamerSdk = g_cCamerOperSdk[lRealHandle];
	if (nullptr == pOperCamerSdk)
	{
		return;
	}
	pOperCamerSdk->drawCorrect(lRealHandle, hDc, dwUser);
}

/*************************************************
函数名:    	fVoiceTalkDataCallBack
函数描述:	回调函数，采集PCM数据，加上wav头
输入参数:   lVoiceComHandle-语音转发句柄
			pRecvDataBuffer-数据缓冲区
			dwBufSize-缓冲区大小
			byAudioFlag-语音数据类型0-本地采集的语音，1-接收到得语音
			pUser-用户数据
输出参数:
返回值:
*************************************************/
void CALLBACK fVoiceTalkDataCallBack(LONG lVoiceComHandle, char *pRecvDataBuffer, DWORD dwBufSize, BYTE byAudioFlag, void *pUser)
{
	//因为当前的噪声使用传感器,所有直接返回,不做处理
	return;
	assert(pRecvDataBuffer);
	CCamerSdkOper *pOperCamerSdk = (CCamerSdkOper*)pUser;

	//0-本地数据，1-DVR发过来的数据
	if (byAudioFlag == 1)
	{
		//数据写入mmio接口，实现音频播放
		//::mmioWrite(pOperCamerSdk->m_hmmio, pRecvDataBuffer, dwBufSize);

		//音频数据回传入类中进行分析
		QByteArray byte(pRecvDataBuffer, dwBufSize);
		emit pOperCamerSdk->sigAnalyzePCMData(byte);
	}
}



void CALLBACK GetManualThermInfoCallback(DWORD dwType, void* lpBuffer, DWORD dwBufLen, void* pUserData)
{
	if (dwType == NET_SDK_CALLBACK_TYPE_DATA)
	{
		LPNET_DVR_THERMOMETRY_UPLOAD lpThermometry = new NET_DVR_THERMOMETRY_UPLOAD;
		memcpy(lpThermometry, lpBuffer, sizeof(*lpThermometry));

		NET_DVR_TIME struAbsTime = { 0 };
		struAbsTime.dwYear = GET_YEAR(lpThermometry->dwAbsTime);
		struAbsTime.dwMonth = GET_MONTH(lpThermometry->dwAbsTime);
		struAbsTime.dwDay = GET_DAY(lpThermometry->dwAbsTime);
		struAbsTime.dwHour = GET_HOUR(lpThermometry->dwAbsTime);
		struAbsTime.dwMinute = GET_MINUTE(lpThermometry->dwAbsTime);
		struAbsTime.dwSecond = GET_SECOND(lpThermometry->dwAbsTime);


		if (lpThermometry->byRuleCalibType == 0) //点测温
		{

		}

		if ((lpThermometry->byRuleCalibType == 1) || (lpThermometry->byRuleCalibType == 2)) //框/线测温
		{
			CCamerSdkOper *pOperCamerSdk = (CCamerSdkOper*)pUserData;
			pOperCamerSdk->m_dTempMax = lpThermometry->struLinePolygonThermCfg.fMaxTemperature;
			pOperCamerSdk->m_dTempMin = lpThermometry->struLinePolygonThermCfg.fMinTemperature;
			pOperCamerSdk->m_dTempAverage = lpThermometry->struLinePolygonThermCfg.fAverageTemperature;

			//addwxy
			pOperCamerSdk->m_cTempMaxPoint.setX(lpThermometry->struHighestPoint.fX);
			pOperCamerSdk->m_cTempMaxPoint.setY(lpThermometry->struHighestPoint.fY);
			pOperCamerSdk->m_cTempMinPoint.setX(lpThermometry->struLowestPoint.fX);
			pOperCamerSdk->m_cTempMinPoint.setY(lpThermometry->struLowestPoint.fY);

			pOperCamerSdk->m_pDevDataCam->m_dAtcTempAverage = pOperCamerSdk->m_dTempAverage;
			pOperCamerSdk->m_pDevDataCam->m_dAtcTempMax = pOperCamerSdk->m_dTempMax;
			pOperCamerSdk->m_pDevDataCam->m_dAtcTempMin = pOperCamerSdk->m_dTempMin;
			//qDebug() << "end temp" << endl;
			//qDebug() << "m_dTempAverage:" << QString::number(pOperCamerSdk->m_dTempAverage);//打印平均温度

		}

		if (lpThermometry != NULL)
		{
			delete lpThermometry;
			lpThermometry = NULL;
		}
	}
	else if (dwType == NET_SDK_CALLBACK_TYPE_STATUS)
	{
		DWORD dwStatus = *(DWORD*)lpBuffer;
		if (dwStatus == NET_SDK_CALLBACK_STATUS_SUCCESS)
		{

		}
		else if (dwStatus == NET_SDK_CALLBACK_STATUS_FAILED)
		{
			DWORD dwErrCode = *(DWORD*)((char *)lpBuffer + 4);
		}
	}


}

void  CALLBACK fVoiceTransPCMDataCallBack(LONG lVoiceComHandle, char *pRecvDataBuffer, DWORD dwBufSize, BYTE byAudioFlag, void* pUser)
{
	//此处的音频数据是由设备发送的编码后数据，可以二进制方式保存文件，也可以解码播放
	
}

CCamerSdkOper::CCamerSdkOper()
{

}

CCamerSdkOper::CCamerSdkOper(CDevDataCam *pDevDataCam)
{
	m_pDevDataCam = pDevDataCam;
	m_mapCmdName.insert(21, A2T("云台上仰"));
	m_mapCmdName.insert(22, A2T("云台下俯"));
	m_mapCmdName.insert(23, A2T("云台左转"));
	m_mapCmdName.insert(24, A2T("云台右转"));
	m_mapCmdName.insert(2, A2T("控制灯光"));
	m_mapCmdName.insert(8, A2T("设置预置点"));
	connect(this, &CCamerSdkOper::sigAnalyzePCMData, this, &CCamerSdkOper::slotAnalyzePCMData, Qt::QueuedConnection);
	m_nSampleInterval = 4;
	m_nAvgInterval = 2;
	m_dDbUprate = 10;
	m_nDbDeviationNum = 5;
	m_nDbNum = 0;
	m_nDbNumDiffer = 0;
	m_nDbNumOld = 0;
	m_dDbDeviation = 0.00;
	m_nCount = 0;
	m_nRollerNum = 6;
	m_nBelogn = 0;
	m_nDrawType = 0;
}

CCamerSdkOper::~CCamerSdkOper()
{
	QString sErr = "";
	stopRealPlay(enCamer, sErr);
	stopRealPlay(enIR, sErr);
	stopVoiceTalk(enVoice, sErr);
	//hjx++在退出时释放相关海康sdk资源
	if (m_pDevDataCam->m_sStruDeviceInfo.lLoginID != -1)
	{
		//注销用户
		NET_DVR_Logout(m_pDevDataCam->m_sStruDeviceInfo.lLoginID);
		//释放 SDK 资源
		NET_DVR_Cleanup();
	}
	g_cCamerOperSdk.clear();
}


void CCamerSdkOper::getDevCfg()
{
	NET_DVR_IPPARACFG_V40 IpAccessCfg;
	memset(&IpAccessCfg, 0, sizeof(IpAccessCfg));
	DWORD  dwReturned;
	m_pDevDataCam->m_sStruDeviceInfo.bIPRet = NET_DVR_GetDVRConfig(m_pDevDataCam->m_sStruDeviceInfo.lLoginID, NET_DVR_GET_IPPARACFG_V40, 0, &IpAccessCfg, sizeof(NET_DVR_IPPARACFG_V40), &dwReturned);
	if (!m_pDevDataCam->m_sStruDeviceInfo.bIPRet)   //不支持ip接入,9000以下设备不支持禁用模拟通道
	{
		for (int i = 0; i < MAX_ANALOG_CHANNUM; i++)
		{
			if (i < m_pDevDataCam->m_sStruDeviceInfo.iDeviceChanNum + 1)
			{
				m_pDevDataCam->m_sStruDeviceInfo.struChanInfo[i].iChanIndex = i + m_pDevDataCam->m_sStruDeviceInfo.iStartChan;  //通道号
				m_pDevDataCam->m_sStruDeviceInfo.struChanInfo[i].bEnable = TRUE;

			}
			else
			{
				m_pDevDataCam->m_sStruDeviceInfo.struChanInfo[i].iChanIndex = -1;
				m_pDevDataCam->m_sStruDeviceInfo.struChanInfo[i].bEnable = FALSE;
			}
		}
	}
	else        //支持IP接入，9000设备
	{
		for (int i = 0; i < MAX_ANALOG_CHANNUM; i++)  //模拟通道
		{
			if (i < m_pDevDataCam->m_sStruDeviceInfo.iDeviceChanNum)
			{
				m_pDevDataCam->m_sStruDeviceInfo.struChanInfo[i].iChanIndex = i + m_pDevDataCam->m_sStruDeviceInfo.iStartChan;
				if (IpAccessCfg.byAnalogChanEnable[i])
				{
					m_pDevDataCam->m_sStruDeviceInfo.struChanInfo[i].bEnable = TRUE;
				}
				else
				{
					m_pDevDataCam->m_sStruDeviceInfo.struChanInfo[i].bEnable = FALSE;
				}

			}
			else//clear the state of other channel
			{
				m_pDevDataCam->m_sStruDeviceInfo.struChanInfo[i].iChanIndex = -1;
				m_pDevDataCam->m_sStruDeviceInfo.struChanInfo[i].bEnable = FALSE;
			}
		}

		//数字通道
		for (int i = 0; i < MAX_IP_CHANNEL; i++)
		{
			if (IpAccessCfg.struStreamMode[i].uGetStream.struChanInfo.byEnable)  //ip通道在线
			{
				m_pDevDataCam->m_sStruDeviceInfo.struChanInfo[i + MAX_ANALOG_CHANNUM].bEnable = TRUE;
				m_pDevDataCam->m_sStruDeviceInfo.struChanInfo[i + MAX_ANALOG_CHANNUM].iChanIndex = i + IpAccessCfg.dwStartDChan;

			}
			else
			{
				m_pDevDataCam->m_sStruDeviceInfo.struChanInfo[i + MAX_ANALOG_CHANNUM].bEnable = FALSE;
				m_pDevDataCam->m_sStruDeviceInfo.struChanInfo[i + MAX_ANALOG_CHANNUM].iChanIndex = -1;
			}
		}


	}
	m_pDevDataCam->m_cMapCamerInfo[enCamer].m_cClientInfo.lChannel = m_pDevDataCam->m_sStruDeviceInfo.struChanInfo[0].iChanIndex;
	m_pDevDataCam->m_cMapCamerInfo[enIR].m_cClientInfo.lChannel = m_pDevDataCam->m_sStruDeviceInfo.struChanInfo[1].iChanIndex;
}

void CCamerSdkOper::getDecoderCfg()
{
	NET_DVR_DECODERCFG_V30 DecoderCfg;
	DWORD  dwReturned;
	BOOL bRet;
	//获取通道解码器信息
	for (int i = 0; i < MAX_CHANNUM_V30; i++)
	{
		if (m_pDevDataCam->m_sStruDeviceInfo.struChanInfo[i].bEnable)
		{
			memset(&DecoderCfg, 0, sizeof(NET_DVR_DECODERCFG_V30));
			bRet = NET_DVR_GetDVRConfig(m_pDevDataCam->m_sStruDeviceInfo.lLoginID, NET_DVR_GET_DECODERCFG_V30, \
				m_pDevDataCam->m_sStruDeviceInfo.struChanInfo[i].iChanIndex, &DecoderCfg, sizeof(NET_DVR_DECODERCFG_V30), &dwReturned);
			if (!bRet)
			{
				continue;
			}
			memcpy(&m_pDevDataCam->m_sStruDeviceInfo.struChanInfo[i].struDecodercfg, &DecoderCfg, sizeof(NET_DVR_DECODERCFG_V30));
		}
	}
}

bool CCamerSdkOper::initAndLogin(QString &sReInfo)
{
	if (!m_pDevDataCam->m_bInit)
	{
		if (!initCamer(sReInfo))
		{
			return false;
		}
	}
	if (!m_pDevDataCam->m_bLogin)
	{
		if (!loginCamer(sReInfo))
		{
			m_pDevDataCam->m_bInit = false;
			m_pDevDataCam->m_bLogin = false;
			return false;
		}
		
	}
	return true;
}

bool CCamerSdkOper::initCamer(QString &sReInfo)
{
	if (NET_DVR_Init())
	{
		m_pDevDataCam->m_bInit = true;
		sReInfo = A2T("云台初始化成功");
		return true;
	}
	else
	{
		m_pDevDataCam->m_bInit = false;
		sReInfo = A2T("云台初始化失败，") + getErrMsg();
		return false;
	}
}

bool CCamerSdkOper::loginCamer(QString &sReInfo)
{
	if (m_pDevDataCam->m_bLogin)
	{
		return true;
	}
	NET_DVR_DEVICEINFO_V30 DeviceInfoTmp;
	memset(&DeviceInfoTmp, 0, sizeof(NET_DVR_DEVICEINFO_V30));
	char *cDeviceIp;
	char *cUserName;
	char *cPassWord;
	QByteArray ba1 = m_pDevDataCam->m_sCamerIp.toLatin1();
	cDeviceIp = ba1.data();
	QByteArray ba2 = m_pDevDataCam->m_sUserName.toLatin1();
	cUserName = ba2.data();
	QByteArray ba3 = m_pDevDataCam->m_sPassWord.toLatin1();
	cPassWord = ba3.data();
	//设置连接时间与重连时间
	int nProt = m_pDevDataCam->m_nCamerPort;
	LONG lLoginID = NET_DVR_Login_V30(cDeviceIp, nProt, cUserName, cPassWord, &DeviceInfoTmp);
	if (lLoginID == -1)
	{
		sReInfo = A2T("云台连接失败,") + getErrMsg();
		m_pDevDataCam->m_bLogin = false;
		return false;
	}
	else
	{
		m_pDevDataCam->m_sStruDeviceInfo.lLoginID = lLoginID;
		m_pDevDataCam->m_sStruDeviceInfo.iDeviceChanNum = DeviceInfoTmp.byChanNum;
		m_pDevDataCam->m_sStruDeviceInfo.iIPChanNum = DeviceInfoTmp.byIPChanNum;
		m_pDevDataCam->m_sStruDeviceInfo.iStartChan = DeviceInfoTmp.byStartChan;
		m_pDevDataCam->m_sStruDeviceInfo.iIPStartChan = DeviceInfoTmp.byStartDChan;
		m_pDevDataCam->m_bLogin = true;
		getDevCfg();                   //获取设备资源信息
		getDecoderCfg();               //获取云台解码器信息
		sReInfo = A2T("云台连接成功");
		return true;
	}
}

bool CCamerSdkOper::login(QString &sReInfo)
{
	return initAndLogin(sReInfo);
}

bool CCamerSdkOper::realPlay(int nDevId, QString &sReInfo)
{
	if (!initAndLogin(sReInfo))
	{
		return false;
	}

	if (!m_pDevDataCam->m_bCheckTemp)
	{
		if (!setSTDConfig(m_pDevDataCam->m_sStruDeviceInfo.lLoginID))
		{
			m_pDevDataCam->m_bCheckTemp = false;
			return false;
		}
		else
		{
			m_pDevDataCam->m_bCheckTemp = true;
		}
	}
	QString sDevName = "";
	if (nDevId == enIR)
	{
		sDevName = A2T("红外相机");
	}
	else if (nDevId == enCamer)
	{
		sDevName = A2T("图像相机");
	}
	SCamerInfo cCamerInfo = m_pDevDataCam->m_cMapCamerInfo[nDevId];
	//1.如果视频已经连接 返回true
	if (cCamerInfo.m_bConStatus)
	{
		sReInfo = A2T("该%1已经开启预览").arg(sDevName);
		return true;
	}
	cCamerInfo.m_cClientInfo.lLinkMode = 0;
	cCamerInfo.m_cClientInfo.sMultiCastIP = NULL;
	cCamerInfo.m_lHandle = NET_DVR_RealPlay_V30(m_pDevDataCam->m_sStruDeviceInfo.lLoginID, &cCamerInfo.m_cClientInfo, NULL, NULL, TRUE);
	int nErr = NET_DVR_GetLastError();
	if (-1 == cCamerInfo.m_lHandle)
	{
		sReInfo = A2T("%1开启预览失败，").arg(sDevName) + getErrMsg();
		cCamerInfo.m_bConStatus = false;
		m_pDevDataCam->m_cMapCamerInfo[nDevId] = cCamerInfo;
		return false;
	}
	else
	{
		sReInfo = A2T("%1开启预览成功").arg(sDevName);
		cCamerInfo.m_bConStatus = true;
		m_pDevDataCam->m_cMapCamerInfo[nDevId] = cCamerInfo;		
		return true;
	}
}

bool CCamerSdkOper::realPlay(int nDevId, HWND hHand, QString &sReInfo)
{
	if (!initAndLogin(sReInfo))
	{
		return false;
	}
	QString sDevName = "";
	if (nDevId == enIR)
	{
		sDevName = A2T("红外相机");
	}
	else if (nDevId == enCamer)
	{
		sDevName = A2T("图像相机");
	}
	if (m_pDevDataCam->m_cMapHandInfo.contains(hHand))
	{
		sReInfo = A2T("该%1已经开启预览").arg(sDevName);
		return true;
	}

	/*SCamerInfo cCamerInfo;
	cCamerInfo.m_cClientInfo.lLinkMode = 1;
	cCamerInfo.m_cClientInfo.sMultiCastIP = NULL;
	cCamerInfo.m_cClientInfo.hPlayWnd = hHand;
	if (nDevId == enCamer)
	{
		//可见光
		cCamerInfo.m_cClientInfo.lChannel = m_pDevDataCam->m_sStruDeviceInfo.struChanInfo[0].iChanIndex;
	}
	else
	{
		//红外
		cCamerInfo.m_cClientInfo.lChannel = m_pDevDataCam->m_sStruDeviceInfo.struChanInfo[1].iChanIndex;
	}
	cCamerInfo.m_lHandle = NET_DVR_RealPlay_V30(m_pDevDataCam->m_sStruDeviceInfo.lLoginID, &cCamerInfo.m_cClientInfo, NULL, NULL, TRUE);*/
	SCamerInfo cCamerInfo;
	NET_DVR_PREVIEWINFO struPlayInfo;
	struPlayInfo.hPlayWnd = hHand; //需要 SDK 解码时句柄设为有效值，仅取流不解码时可设为空
	if (nDevId == enCamer)
	{
		//可见光
		struPlayInfo.lChannel = m_pDevDataCam->m_sStruDeviceInfo.struChanInfo[0].iChanIndex;
	}
	else
	{
		//红外
		struPlayInfo.lChannel = m_pDevDataCam->m_sStruDeviceInfo.struChanInfo[1].iChanIndex;
	}
	struPlayInfo.dwStreamType = 0; //0-主码流，1-子码流，2-码流 3，3-码流 4，以此类推
	struPlayInfo.dwLinkMode = 0; //0- TCP 方式，1- UDP 方式，2- 多播方式，3- RTP 方式，4-RTP/RTSP，5-RSTP/HTTP
	struPlayInfo.bBlocked = 0; //0- 非阻塞取流，1- 阻塞取流
	cCamerInfo.m_lHandle = NET_DVR_RealPlay_V40(m_pDevDataCam->m_sStruDeviceInfo.lLoginID, &struPlayInfo, nullptr, nullptr);

	
	if (-1 == cCamerInfo.m_lHandle)
	{
		sReInfo = A2T("%1开启预览失败，").arg(sDevName) + getErrMsg();
		cCamerInfo.m_bConStatus = false;
		return false;
	}
	else
	{
		sReInfo = A2T("%1开启预览成功。").arg(sDevName);
		cCamerInfo.m_bConStatus = true;
		m_pDevDataCam->m_cMapHandInfo.insert(hHand, cCamerInfo);

		//addwxy 新增红外测温配置
		if (nDevId == enIR)
		{
			//if (!setSTDConfig(m_pDevDataCam->m_sStruDeviceInfo.lLoginID))
			//{
			//	//测温配置失败
			//}

			if (!NET_DVR_RigisterDrawFun(cCamerInfo.m_lHandle, DrawTempText, NULL))
			{
				//回调画图失败
			}
			else
			{
				g_cCamerOperSdk.insert(cCamerInfo.m_lHandle, this);
				//画图回调成功
			}
		}
		if (nDevId == enCamer)
		{
			if (m_nDrawType == 0)
			{
				if (!NET_DVR_RigisterDrawFun(cCamerInfo.m_lHandle, DrawRollerNum, NULL))
				{
					//回调画图失败
				}
				else
				{
					g_cCamerOperSdk.insert(cCamerInfo.m_lHandle, this);
					//画图回调成功
				}
			}
			else if(m_nDrawType == 1)
			{
				if (!NET_DVR_RigisterDrawFun(cCamerInfo.m_lHandle, DrawCorrectData, NULL))
				{
					//回调画图失败
				}
				else
				{
					g_cCamerOperSdk.insert(cCamerInfo.m_lHandle, this);
					//画图回调成功
				}
			}
		}
		return true;
	}
}

bool CCamerSdkOper::realPlay(int nDevId, HWND hHand, QWidget * pWidget, QString & sReInfo)
{
	return false;
}

bool CCamerSdkOper::stopRealPlay(int nDevId, QString &sReInfo)
{
	SCamerInfo cCamerInfo = m_pDevDataCam->m_cMapCamerInfo[nDevId];
	QString sDevName = "";
	if (nDevId == enIR)
	{
		sDevName = A2T("红外相机");
	}
	else if (nDevId == enCamer)
	{
		sDevName = A2T("图像相机");
	}
	//1.如果未连接或者连接失败 返回true
	if (cCamerInfo.m_bConStatus == false)
	{
		sReInfo = A2T("%1未开启预览").arg(sDevName);
		return true;
	}
	//2.如果正在录像 停止录像
	if (cCamerInfo.m_bIsRecording)
	{
		sReInfo = A2T("%1正在，执行停止录像，").arg(sDevName);
		stopRecordVideo(nDevId, sReInfo);
		cCamerInfo.m_bIsRecording = false;
	}
	//3.停止预览
	if (NET_DVR_StopRealPlay(cCamerInfo.m_lHandle))
	{
		sReInfo += A2T("%1停止预览成功。").arg(sDevName);
		cCamerInfo.resetData();
		m_pDevDataCam->m_cMapCamerInfo[nDevId] = cCamerInfo;
		return true;
	}
	else
	{
		sReInfo += (A2T("%1停止预览失败，").arg(sDevName) + getErrMsg());
		cCamerInfo.resetData();
		m_pDevDataCam->m_cMapCamerInfo[nDevId] = cCamerInfo;
		return false;
	}
}

bool CCamerSdkOper::stopRealPlay(HWND hHand, QString &sReInfo)
{
	if (!m_pDevDataCam->m_cMapHandInfo.contains(hHand))
	{
		sReInfo = A2T("设备未开启预览。");
		return true;
	}
	SCamerInfo cCamerInfo = m_pDevDataCam->m_cMapHandInfo[hHand];
	//1.如果未连接或者连接失败 返回true
	if (cCamerInfo.m_bConStatus == false)
	{
		sReInfo = A2T("设备未开启预览。");
		return true;
	}
	//2.如果正在录像 停止录像
	if (cCamerInfo.m_bIsRecording)
	{
		sReInfo = A2T("正在录像，执行停止录像，");
		stopRecordVideo(hHand, sReInfo);
		cCamerInfo.m_bIsRecording = false;
	}
	//3.停止预览
	if (NET_DVR_StopRealPlay(cCamerInfo.m_lHandle))
	{
		sReInfo += A2T("停止预览成功。");
		m_pDevDataCam->m_cMapHandInfo.remove(hHand);
		return true;
	}
	else
	{
		sReInfo += (A2T("停止预览失败，") + getErrMsg());
		m_pDevDataCam->m_cMapHandInfo.remove(hHand);
		return false;
	}
}


bool CCamerSdkOper::ptzPresetOther(int nPresetIndex, int nCmd, QString &sReInfo)
{
	if (!initAndLogin(sReInfo))
	{
		return false;
	}
	LONG lLoginID = m_pDevDataCam->m_sStruDeviceInfo.lLoginID;
	LONG lChannel = m_pDevDataCam->m_sStruDeviceInfo.struChanInfo[0].iChanIndex;
	if (nCmd == GOTO_PRESET)
	{

		if (NET_DVR_PTZPreset_Other(lLoginID, lChannel, GOTO_PRESET, nPresetIndex))
		{
			sReInfo += A2T("云台转动预置点") + QString::number(nPresetIndex) + A2T("成功");
			return true;
		}
		else
		{
			sReInfo += (A2T("云台转动预置点") + QString::number(nPresetIndex) + A2T("失败") + getErrMsg());
			return false;
		}
	}
	else if (nCmd == SET_PRESET)
	{
		if (NET_DVR_PTZPreset_Other(lLoginID, lChannel, SET_PRESET, nPresetIndex))
		{
			sReInfo += A2T("云台设置预置点") + QString::number(nPresetIndex) + A2T("成功");
			return true;
		}
		else
		{
			sReInfo += (A2T("云台设置预置点") + QString::number(nPresetIndex) + A2T("失败") + getErrMsg());
			return false;
		}
	}
	else
	{
		sReInfo += A2T("未知命令不执行");
		return false;
	}
}

bool CCamerSdkOper::capture(int nDevId, QString & sPath, QString &sReInfo)
{
	if (nDevId == enCamer)
	{
		return captureImg(sPath, sReInfo);
	}
	else
	{
		return captureIr(sPath, sReInfo);
	}
}

bool CCamerSdkOper::ptzControlOther(int nCmd, int nSpeed, bool bRun, QString &sReInfo)
{
	if (!initAndLogin(sReInfo))
	{
		return false;
	}
	LONG lLoginID = m_pDevDataCam->m_sStruDeviceInfo.lLoginID;
	LONG lChannel = m_pDevDataCam->m_sStruDeviceInfo.struChanInfo[0].iChanIndex;
	int nRun = 0;
	if (bRun == false)nRun = 1;
	if (nSpeed >= 1)
	{
		if (NET_DVR_PTZControlWithSpeed_Other(lLoginID, lChannel, nCmd, nRun, nSpeed))
		{
			if (nRun == 0)
			{
				sReInfo += A2T("云台命令") + m_mapCmdName.value(nCmd) + A2T("执行成功");
			}
			else
			{
				sReInfo += A2T("云台命令") + m_mapCmdName.value(nCmd) + A2T("停止");
			}
			return true;
		}
		else
		{
			sReInfo += A2T("云台命令") + m_mapCmdName.value(nCmd) + A2T("执行失败") + getErrMsg();
			return false;
		}
	}
	else
	{
		if (NET_DVR_PTZControl_Other(lLoginID, lChannel, nCmd, nRun))
		{
			if (nRun == 0)
			{
				sReInfo += A2T("云台命令") + m_mapCmdName.value(nCmd) + A2T("执行成功");
			}
			else
			{
				sReInfo += A2T("云台命令") + m_mapCmdName.value(nCmd) + A2T("停止");
			}
			return true;
		}
		else
		{
			if (nRun == 0)
			{
				sReInfo += A2T("云台命令") + m_mapCmdName.value(nCmd) + A2T("执行失败") + getErrMsg();
			}
			else
			{
				sReInfo += A2T("云台命令") + m_mapCmdName.value(nCmd) + A2T("停止执行失败") + getErrMsg();
			}
			
			return false;
		}
	}
	return false;
}

bool CCamerSdkOper::captureIr(QString & sPath, QString &sReInfo)
{
	if (!initAndLogin(sReInfo))
	{
		return false;
	}

#if 0
	//原来的代码
	LONG lLoginID = m_pDevDataCam->m_sStruDeviceInfo.lLoginID;
	LONG lChannel = m_pDevDataCam->m_sStruDeviceInfo.struChanInfo[1].iChanIndex;     //0是可见光 1是红外
	NET_DVR_JPEGPARA JpgPara = { 0 };
	JpgPara.wPicSize = 0xff;
	JpgPara.wPicQuality = 0;
	QString sPathData = sPath + QDateTime::currentDateTime().toString("yyyy-MM-dd-hh-mm-ss") + ".data";
	sPath = sPath + QDateTime::currentDateTime().toString("yyyy-MM-dd-hh-mm-ss") + ".jpg";
	char *cRecName, *cRecNameData;
	QByteArray ba = sPath.toLatin1();
	cRecName = ba.data();
	QByteArray ba1 = sPathData.toLatin1();
	cRecNameData = ba1.data();
	NET_DVR_JPEGPICTURE_WITH_APPENDDATA struJpegPictureWithAppendAata = { 0 };
	char szLan[256] = { 0 };
#endif

#if 1
	LONG lLoginID = m_pDevDataCam->m_sStruDeviceInfo.lLoginID;
	LONG lChannel = m_pDevDataCam->m_sStruDeviceInfo.struChanInfo[1].iChanIndex;     //0是可见光 1是红外
	NET_DVR_JPEGPARA JpgPara = { 0 };
	JpgPara.wPicSize = 0xff;
	JpgPara.wPicQuality = 0;
	sPath = sPath + QDateTime::currentDateTime().toString("yyyyMM") + "/"+ QDateTime::currentDateTime().toString("dd")+"/";
	QDir folder(sPath);// 创建QDir对象
	if (!folder.exists())
	{
		// 文件夹不存在，则创建
		if (folder.mkpath("."))
		{
		}
	}
	// 创建随机数生成器
	QRandomGenerator *generator = QRandomGenerator::global();
	// 生成两位随机数
	int randomNum = generator->bounded(90) + 10; // 生成范围 [10, 99]
	QString sPathData = sPath + QDateTime::currentDateTime().toString("yyyy-MM-dd-hh-mm-ss-zzz")+QString::number(randomNum) + ".data";
	sPath = sPath + QDateTime::currentDateTime().toString("yyyy-MM-dd-hh-mm-ss-zzz")+ QString::number(randomNum) + ".jpg";
	char *cRecNameData;
	QByteArray ba1 = sPathData.toLatin1();
	cRecNameData = ba1.data();
	NET_DVR_JPEGPICTURE_WITH_APPENDDATA struJpegPictureWithAppendAata = { 0 };
	char szLan[256] = { 0 };
#endif
	if (struJpegPictureWithAppendAata.pJpegPicBuff == NULL)
	{
		struJpegPictureWithAppendAata.pJpegPicBuff = new char[2 * 1024 * 1024];
		memset(struJpegPictureWithAppendAata.pJpegPicBuff, 0, 2 * 1024 * 1024);
	}
	if (struJpegPictureWithAppendAata.pP2PDataBuff == NULL)
	{
		struJpegPictureWithAppendAata.pP2PDataBuff = new char[2 * 1024 * 1024];
		memset(struJpegPictureWithAppendAata.pP2PDataBuff, 0, 2 * 1024 * 1024);
	}

	if (struJpegPictureWithAppendAata.pVisiblePicBuff == NULL)//可见光图至少为4M
	{
		struJpegPictureWithAppendAata.pVisiblePicBuff = new char[10 * 1024 * 1024];
		memset(struJpegPictureWithAppendAata.pVisiblePicBuff, 0, 10 * 1024 * 1024);
	}
	if (NET_DVR_CaptureJPEGPicture_WithAppendData(lLoginID, lChannel, &struJpegPictureWithAppendAata))
	{
		if (struJpegPictureWithAppendAata.dwP2PDataLen > 0 && struJpegPictureWithAppendAata.pP2PDataBuff != NULL)
		{
			/*char cFilenameData[256] = { 0 };
			memcpy(cFilenameData, cRecNameData, 256*sizeof(char));*/
			sReInfo += A2T("测温数据采集成功");
			DWORD dwWrittenBytesData = 0;
			HANDLE hFileData = CreateFileA(cRecNameData, GENERIC_WRITE, FILE_SHARE_READ, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
			if (hFileData != INVALID_HANDLE_VALUE)
			{
				DWORD dwRet = WriteFile(hFileData, struJpegPictureWithAppendAata.pP2PDataBuff, struJpegPictureWithAppendAata.dwP2PDataLen, &dwWrittenBytesData, NULL);
				if (dwRet == 0 || dwWrittenBytesData < struJpegPictureWithAppendAata.dwP2PDataLen)
				{
					DWORD dwError = GetLastError();
				}
				delete struJpegPictureWithAppendAata.pJpegPicBuff;
				delete struJpegPictureWithAppendAata.pP2PDataBuff;
				delete struJpegPictureWithAppendAata.pVisiblePicBuff;
				CloseHandle(hFileData);
				hFileData = NULL;
			}
			NET_DVR_JPEGPARA JpgPara = { 0 };
			JpgPara.wPicSize = 0xff;
			JpgPara.wPicQuality = 0;
			char *cRecName;
			QByteArray ba = sPath.toLatin1();
			cRecName = ba.data();
			if (NET_DVR_CaptureJPEGPicture(lLoginID, lChannel, &JpgPara, cRecName))
			{
				sReInfo += A2T("红外测温图片抓取成功");
				return true;
			}
			else
			{
				sReInfo += A2T("红外测温图片抓取失败") + getErrMsg();
				return false;
			}
		}
		return true;
	}
	else
	{
		delete struJpegPictureWithAppendAata.pJpegPicBuff;
		delete struJpegPictureWithAppendAata.pP2PDataBuff;
		delete struJpegPictureWithAppendAata.pVisiblePicBuff;
		sReInfo += A2T("测温数据采集失败") + getErrMsg();
		return false;
	}
}

bool CCamerSdkOper::captureImg(QString & sPath, QString &sReInfo)
{
	NET_DVR_JPEGPARA JpgPara = { 0 };
	JpgPara.wPicSize = 0xff;
	JpgPara.wPicQuality = 0;
	sPath = sPath + QDateTime::currentDateTime().toString("yyyyMM") + "/" + QDateTime::currentDateTime().toString("dd") + "/";
	QDir folder(sPath);// 创建QDir对象
	if (!folder.exists())
	{
		// 文件夹不存在，则创建
		if (folder.mkpath("."))
		{
		}
	}
	// 创建随机数生成器
	QRandomGenerator *generator = QRandomGenerator::global();
	// 生成两位随机数
	int randomNum = generator->bounded(90) + 10; // 生成范围 [10, 99]

	sPath = sPath + QDateTime::currentDateTime().toString("yyyy-MM-dd-hh-mm-ss-zzz")+QString::number(randomNum) + ".jpg";
	char *cRecName;
	QByteArray ba = sPath.toLatin1();
	cRecName = ba.data();
	LONG lLoginID = m_pDevDataCam->m_sStruDeviceInfo.lLoginID;
	LONG lChannel = m_pDevDataCam->m_sStruDeviceInfo.struChanInfo[0].iChanIndex;     //0是可见光 1是红外
	if (NET_DVR_CaptureJPEGPicture(lLoginID, lChannel, &JpgPara, cRecName))
	{
		sReInfo += A2T("可见光图片抓取成功");
		return true;
	}
	else
	{
		sReInfo += A2T("可见光图片抓取失败");
		return false;
	}
}

QString CCamerSdkOper::getErrMsg()
{
	QString sErr = A2T("错误原因：");
	DWORD err = NET_DVR_GetLastError();
	sErr +=A2T("错误码:%1").arg(err);
	switch (err)
	{
	case 0:
		sErr += A2T("没有错误。");
		break;
	case 1:
		sErr += A2T("用户名密码错误。注册时输入的用户名或者密码错误。");
		break;
	case 2:
		sErr += A2T("权限不足。一般和通道相关，例如有预览通道1权限，无预览通道2权限，即有预览权限但不完全，预览通道2返回此错误。");
		break;
	case 3:
		sErr += A2T("SDK未初始化。必须先调用NET_DVR_Init，该接口是调用其他SDK函数的前提且一个程序进程只需要调用一次。");
		break;
	case 4:
		sErr += A2T("通道号错误。设备通道分模拟通道和数字通道（IP通道），NET_DVR_Login_V40登录设备成功之后会返回设备支持的通道个数和起始通道号取值，详见“通道和通道号号相关说明”。");
		break;
	case 5:
		sErr += A2T("设备总的连接数超过最大。例如网络摄像机只支持6路预览，预览第7路即会返回失败，错误码返回5。不同设备性能不一样，支持路数也不同。");
		break;
	case 6:
		sErr += A2T("版本不匹配。SDK和设备的版本不匹配。");
		break;
	case 7:
		sErr += A2T("连接设备失败。设备不在线或网络原因引起的连接超时等。");
		break;
	case 8:
		sErr += A2T("向设备发送失败。");
		break;
	case 9:
		sErr += A2T("从设备接收数据失败。");
		break;
	case 10:
		sErr += A2T("从设备接收数据超时。");
		break;
	case 11:
		sErr += A2T("传送的数据有误。发送给设备或者从设备接收到的数据错误，如远程参数配置时输入设备不支持的值。");
		break;
	case 12:
		sErr += A2T("调用次序错误。");
		break;
	case 13:
		sErr += A2T("无此权限。用户对某个功能模块的权限，例如无预览权限用户预览返回此错误。");
		break;
	case 14:
		sErr += A2T("设备命令执行超时。");
		break;
	case 15:
		sErr += A2T("串口号错误。指定的设备串口号不存在。");
		break;
	case 16:
		sErr += A2T("报警端口错误。指定的设备报警输入或者输出端口不存在。");
		break;
	case 17:
		sErr += A2T("参数错误。SDK接口中给入的输入或输出参数为空，或者参数格式或值不符合要求。");
		break;
	case 18:
		sErr += A2T("设备通道处于错误状态");
		break;
	case 19:
		sErr += A2T("设备无硬盘。当设备无硬盘时，对设备的录像文件、硬盘配置等操作失败。");
		break;
	case 20:
		sErr += A2T("硬盘号错误。当对设备进行硬盘管理操作时，指定的硬盘号不存在时返回该错误。");
		break;
	case 21:
		sErr += A2T("设备硬盘满。");
		break;
	case 22:
		sErr += A2T("设备硬盘出错");
		break;
	case 23:
		sErr += A2T("设备不支持。");
		break;
	case 24:
		sErr += A2T("设备忙。");
		break;
	case 25:
		sErr += A2T("设备修改不成功。");
		break;
	case 26:
		sErr += A2T("密码输入格式不正确");
		break;
	case 27:
		sErr += A2T("硬盘正在格式化，不能启动操作。");
		break;
	case 28:
		sErr += A2T("设备资源不足。");
		break;
	case 29:
		sErr += A2T("设备操作失败。");
		break;
	case 30:
		sErr += A2T("语音对讲、语音广播操作中采集本地音频或打开音频输出失败。");
		break;
	case 31:
		sErr += A2T("设备语音对讲被占用。");
		break;
	case 32:
		sErr += A2T("时间输入不正确。");
		break;
	case 33:
		sErr += A2T("回放时设备没有指定的文件。");
		break;
	case 34:
		sErr += A2T("创建文件出错。本地录像、保存图片、获取配置文件和远程下载录像时创建文件失败。");
		break;
	case 35:
		sErr += A2T("打开文件出错。可能因为文件不存在或者路径错误。");
		break;
	case 36:
		sErr += A2T("上次的操作还没有完成。");
		break;
	case 37:
		sErr += A2T("获取当前播放的时间出错。");
		break;
	case 38:
		sErr += A2T("播放出错。");
		break;
	case 39:
		sErr += A2T("文件格式不正确。");
		break;
	default:
		sErr += A2T("其他错误。");
		break;
	}
	return sErr;
}

//设置测温配置 addwxy
bool CCamerSdkOper::setSTDConfig(LONG lUserID)
{
	DWORD dwChannel = 2;  //热成像通道
	char *m_pOutBuf = new char[ISAPI_OUT_LEN];
	memset(m_pOutBuf, 0, ISAPI_OUT_LEN);

	char *m_pStatusBuf = new char[ISAPI_STATUS_LEN];
	memset(m_pStatusBuf, 0, ISAPI_STATUS_LEN);

	//测温基本参数配置
	NET_DVR_STD_CONFIG struStdConfigA = { 0 };
	struStdConfigA.lpCondBuffer = &dwChannel;
	struStdConfigA.dwCondSize = sizeof(dwChannel);
	struStdConfigA.lpInBuffer = NULL;
	struStdConfigA.dwInSize = 0;

	////测温基本参数配置
	NET_DVR_STD_CONFIG struStdConfig = { 0 };
	struStdConfig.lpCondBuffer = &dwChannel;
	struStdConfig.dwCondSize = sizeof(dwChannel);
	struStdConfig.lpInBuffer = NULL;
	struStdConfig.dwInSize = 0;

	NET_DVR_THERMOMETRY_BASICPARAM struThermBasicParam = { 0 };
	struStdConfig.lpOutBuffer = (LPVOID)&struThermBasicParam;
	struStdConfig.dwOutSize = sizeof(struThermBasicParam);

	struStdConfig.lpStatusBuffer = m_pStatusBuf;
	struStdConfig.dwStatusSize = ISAPI_STATUS_LEN;

	DWORD dwReturned = 0;
	if (!NET_DVR_GetSTDConfig(lUserID, NET_DVR_GET_THERMOMETRY_BASICPARAM, &struStdConfig))
	{
		return false;
	}

	struThermBasicParam.byEnabled = 1;          //使能：0- 不启用，1- 启用
	struThermBasicParam.byStreamOverlay = 1;    //码流是否叠加温度信息：0- 否，1- 是
	struThermBasicParam.byThermometryRange = 1; //测温范围（这里以摄氏度为单位计算，其他单位由上层自行转换）：0- 默认值，1- (-20~150)，2- (0~550) 
	struThermBasicParam.byThermometryUnit = 0;  //测温单位（所有测温配置功能中温度参数对应的单位）: 0- 摄氏度（℃），1- 华氏度（℉），2- 开尔文(K) 
	struThermBasicParam.byPictureOverlay = 1;
	struThermBasicParam.byDisplayAverageTemperatureEnabled = 1;
	struThermBasicParam.byThermometryInfoDisplayposition = 1;
	struThermBasicParam.byDisplayCentreTemperatureEnabled = 1;
	struThermBasicParam.byDisplayMaxTemperatureEnabled = 1;
	struThermBasicParam.byDisplayMinTemperatureEnabled = 1;
	//struThermBasicParam.byThermometryCurve = 1;
	struStdConfig.lpInBuffer = (LPVOID)&struThermBasicParam;
	struStdConfig.dwInSize = sizeof(struThermBasicParam);

	if (!NET_DVR_SetSTDConfig(lUserID, NET_DVR_SET_THERMOMETRY_BASICPARAM, &struStdConfig))
	{
		return false;
	}


	NET_DVR_REALTIME_THERMOMETRY_COND struThermCond = { 0 };
	struThermCond.dwSize = sizeof(struThermCond);
	struThermCond.byRuleID = 0;       //规则ID，0代表获取全部规则，具体规则ID从1开始
	struThermCond.dwChan = dwChannel; //从1开始，0xffffffff代表获取全部通道
	struThermCond.byMode = 1;
	struThermCond.wInterval = 1;
	LONG lHandle = NET_DVR_StartRemoteConfig(m_pDevDataCam->m_sStruDeviceInfo.lLoginID, NET_DVR_GET_REALTIME_THERMOMETRY, &struThermCond, sizeof(struThermCond), GetManualThermInfoCallback, this);
	if (lHandle < 0)
	{
		return false;
	}
	else
	{
		return true;
	}
}

//画温度信息 addwxy
void CCamerSdkOper::drawTempInfo(LONG lRealHandle, HDC hDc, DWORD dwUser)
{
	bool bFindHwnd = false;
	HWND hwnd;
	for (QMap<HWND, SCamerInfo>::Iterator i = m_pDevDataCam->m_cMapHandInfo.begin(); i != m_pDevDataCam->m_cMapHandInfo.end(); i++)
	{
		if (i.value().m_lHandle == lRealHandle)
		{
			bFindHwnd = true;
			hwnd = i.key();
		}
	}
	if (false == bFindHwnd)
	{
		return;
	}

	int nRectLength = 40;
	int nTextHeight = 50;
	int nTextWidth = 200;

	RECT clientRect;
	GetClientRect(hwnd, &clientRect);//获取窗口客户区坐标

	double dMaxX = clientRect.right*m_cTempMaxPoint.x();
	double dMaxY = clientRect.bottom*m_cTempMaxPoint.y();

	double dMinX = clientRect.right*m_cTempMinPoint.x();
	double dMinY = clientRect.bottom*m_cTempMinPoint.y();

	// 获取客户区的宽度和高度
	int clientWidth = clientRect.right - clientRect.left;
	int clientHeight = clientRect.bottom - clientRect.top;

	// 创建绿色画笔 宽度为8像素
	COLORREF greenColor = 0x0000FF00; // 绿色 (0, 255, 0)
	HPEN hGreenPen = CreatePen(PS_SOLID, 8, greenColor);
	// 选择绿色画笔到设备环境中
	HPEN hOldPen = (HPEN)SelectObject(hDc, hGreenPen);
	
	//文字显示区域
	RECT rectMaxText;
	//rectMaxText.left = 10;//矩形左上角的 x 坐标
	//rectMaxText.top = clientHeight - 50;//矩形左上角的 y 坐标
	//rectMaxText.right = 150;//表示矩形右下角的 x 坐标
	//rectMaxText.bottom = clientHeight - 30;//矩形右下角的 y 坐标
	rectMaxText.left = dMaxX - nRectLength;;//矩形左上角的 x 坐标
	rectMaxText.top = dMaxY - nRectLength;//矩形左上角的 y 坐标
	rectMaxText.right = dMaxX + nRectLength;//表示矩形右下角的 x 坐标
	rectMaxText.bottom = dMaxY + nRectLength;//矩形右下角的 y 坐标
	RECT rectMinText;
	//rectMinText.left = 10;//矩形左上角的 x 坐标
	//rectMinText.top = clientHeight - 25;//矩形左上角的 y 坐标
	//rectMinText.right = 150;//表示矩形右下角的 x 坐标
	//rectMinText.bottom = clientHeight - 5;//矩形右下角的 y 坐标
	rectMinText.left = dMinX - nRectLength;//矩形左上角的 x 坐标
	rectMinText.top = dMinY - nRectLength;//矩形左上角的 y 坐标
	rectMinText.right = dMinX + nRectLength;//表示矩形右下角的 x 坐标
	rectMinText.bottom = dMinY + nRectLength;//矩形右下角的 y 坐标

	char *pMaxValue;
	char *pMinValue;
	QString strMaxValue = A2T("Max: %1 ℃").arg(m_dTempMax);
	QString strMinValue = A2T("Min: %1 ℃").arg(m_dTempMin);
	QByteArray baMax = strMaxValue.toLocal8Bit();
	QByteArray baMin = strMinValue.toLocal8Bit();
	pMaxValue = baMax.data();
	pMinValue = baMin.data();
	SetTextColor(hDc, greenColor); // 设置文字颜色为绿色
	::DrawTextA(hDc, pMaxValue, strlen(pMaxValue), &rectMaxText, DT_LEFT);//最大值
	::DrawTextA(hDc, pMinValue, strlen(pMinValue), &rectMinText, DT_LEFT);//最小值

	// 恢复原来的画笔
	SelectObject(hDc, hOldPen);
	// 删除创建的绿色画笔
	DeleteObject(hGreenPen);

}

void CCamerSdkOper::drawRollerNum(LONG lRealHandle, HDC hDc, DWORD dwUser)
{
	bool bFindHwnd = false;
	HWND hwnd;
	for (QMap<HWND, SCamerInfo>::Iterator i = m_pDevDataCam->m_cMapHandInfo.begin(); i != m_pDevDataCam->m_cMapHandInfo.end(); i++)
	{
		if (i.value().m_lHandle == lRealHandle)
		{
			bFindHwnd = true;
			hwnd = i.key();
		}
	}
	if (false == bFindHwnd)
	{
		return;
	}
	// 创建绿色画笔 宽度为8像素
	COLORREF greenColor = 0x0000FF00; // 绿色 (0, 255, 0)
	RECT rect;
	GetClientRect(hwnd, &rect);//获取窗口客户区坐标
	// 计算右上角的起始位置
	int boxWidth = 300;
	int boxHeight = 200;
	RECT boxRect;
	boxRect.left = rect.right - boxWidth;
	boxRect.top = rect.top;
	boxRect.right = rect.right;
	boxRect.bottom = rect.top + boxHeight;

	// 设置文字颜色为绿色
	SetTextColor(hDc, greenColor);
	SetBkMode(hDc, TRANSPARENT); // 文字背景透明

	// 绘制 "96号" 使用 16 号加粗字体
	HFONT hFont16Bold = CreateFontA(40, 0, 0, 0, FW_BOLD, FALSE, FALSE, FALSE, ANSI_CHARSET,
		OUT_DEFAULT_PRECIS, CLIP_DEFAULT_PRECIS, DEFAULT_QUALITY,
		DEFAULT_PITCH | FF_SWISS, "SimSun");
	HGDIOBJ hOldFont = SelectObject(hDc, hFont16Bold);
	QByteArray baRollerNum;
	baRollerNum = m_sRollerDesc.toLocal8Bit();
	
	RECT textRect1 = boxRect;
	textRect1.top = boxRect.top + 10; // 上半部分用于 "96号"
	textRect1.bottom = boxRect.top + 100; // 上半部分用于 "96号"
	DrawTextA(hDc, baRollerNum, -1, &textRect1, DT_CENTER | DT_VCENTER | DT_SINGLELINE);

	// 绘制 "托辊" 使用 12 号加粗字体
	HFONT hFont12Bold = CreateFontA(40, 0, 0, 0, FW_BOLD, FALSE, FALSE, FALSE, ANSI_CHARSET,
		OUT_DEFAULT_PRECIS, CLIP_DEFAULT_PRECIS, DEFAULT_QUALITY,
		DEFAULT_PITCH | FF_SWISS, "SimSun");
	SelectObject(hDc, hFont12Bold);

	RECT textRect2 = textRect1;
	textRect2.top = textRect1.bottom; // 下半部分用于 "托辊"
	textRect2.bottom = textRect1.bottom + 60;
	DrawTextA(hDc, "托辊", -1, &textRect2, DT_CENTER | DT_VCENTER | DT_SINGLELINE);

	// 恢复原来的字体
	SelectObject(hDc, hOldFont);
	DeleteObject(hFont16Bold);
	DeleteObject(hFont12Bold);
}

void CCamerSdkOper::setRollerNum(int nNum, int nBologn, QString sRollerDesc)
{
	m_sRollerDesc = sRollerDesc;
	m_nRollerNum = nNum;
	m_nBelogn = nBologn;
}

void CCamerSdkOper::setCorrectData(double dLeftRectifyValue, double dRightRectifyValue, int nRectifySetValue, int nRectifySetValueTwo, QPointF BeltEdgePf1, QPointF BeltEdgePf2, QPointF BeltEdgePf3, QPointF BeltEdgePf4, int nIsHaveBeltState, bool bBeltState, int nDrawType)
{
	m_dLeftRectifyValue = dLeftRectifyValue;
	m_dRightRectifyValue = dRightRectifyValue;
	m_nRectifySetValue = nRectifySetValue;
	m_nRectifySetValueTwo = nRectifySetValueTwo;
	m_BeltEdgePf1 = BeltEdgePf1;
	m_BeltEdgePf2 = BeltEdgePf2;
	m_BeltEdgePf3 = BeltEdgePf3;
	m_BeltEdgePf4 = BeltEdgePf4;
	m_nIsHaveBeltState = nIsHaveBeltState;
	m_bBeltState = bBeltState;
	m_nDrawType = nDrawType;
}

void CCamerSdkOper::drawCorrect(LONG lRealHandle, HDC hDc, DWORD dwUser)
{
	bool bFindHwnd = false;
	HWND hwnd;
	for (QMap<HWND, SCamerInfo>::Iterator i = m_pDevDataCam->m_cMapHandInfo.begin(); i != m_pDevDataCam->m_cMapHandInfo.end(); i++)
	{
		if (i.value().m_lHandle == lRealHandle)
		{
			bFindHwnd = true;
			hwnd = i.key();
		}
	}
	if (false == bFindHwnd)
	{
		return;
	}

	RECT clientRect;
	GetClientRect(hwnd, &clientRect);//获取窗口客户区坐标

	// 获取客户区的宽度和高度
	int clientWidth = clientRect.right - clientRect.left;
	int clientHeight = clientRect.bottom - clientRect.top;

	HPEN hGreenPen = CreatePen(PS_SOLID, 8, 0x00FF00);
	HPEN hRedPen = CreatePen(PS_SOLID, 8, 0x0000FF);
	HPEN hYellowPen = CreatePen(PS_SOLID, 8, 0x00FFFF);
	HPEN hGrayPen = CreatePen(PS_SOLID, 8, 0x808080);
	HPEN hOldPen;
	if (m_nIsHaveBeltState == 0)
	{
		if (m_dLeftRectifyValue <= m_nRectifySetValueTwo)//阈值是5cm
		{
			hOldPen = (HPEN)SelectObject(hDc, hRedPen);
		}
		else if (m_dLeftRectifyValue > m_nRectifySetValueTwo && m_dLeftRectifyValue <= m_nRectifySetValue)//阈值是5cm
		{
			hOldPen = (HPEN)SelectObject(hDc, hYellowPen);
		}
		else
		{
			hOldPen = (HPEN)SelectObject(hDc, hGreenPen);
		}
	}
	else
	{
		if (m_bBeltState)
		{
			if (m_dLeftRectifyValue <= m_nRectifySetValueTwo)//阈值是5cm
			{
				hOldPen = (HPEN)SelectObject(hDc, hRedPen);
			}
			else if (m_dLeftRectifyValue > m_nRectifySetValueTwo && m_dLeftRectifyValue <= m_nRectifySetValue)//阈值是5cm
			{
				hOldPen = (HPEN)SelectObject(hDc, hYellowPen);
			}
			else
			{
				hOldPen = (HPEN)SelectObject(hDc, hGreenPen);
			}
		}
		else
		{
			hOldPen = (HPEN)SelectObject(hDc, hGrayPen);
		}
	}

	//画第一条线
	::MoveToEx(hDc, MulDiv(m_BeltEdgePf1.x(), clientWidth, 1920), MulDiv(m_BeltEdgePf1.y(), clientHeight, 1080), NULL);// 将绘图点移动到直线起点
	::LineTo(hDc, MulDiv(m_BeltEdgePf4.x(), clientWidth, 1920), MulDiv(m_BeltEdgePf4.y(), clientHeight, 1080));//画直线到指定的终点

	if (m_nIsHaveBeltState == 0)
	{
		if (m_dRightRectifyValue <= m_nRectifySetValueTwo)//阈值是5cm
		{
			hOldPen = (HPEN)SelectObject(hDc, hRedPen);
		}
		else if (m_dRightRectifyValue > m_nRectifySetValueTwo && m_dRightRectifyValue <= m_nRectifySetValue)//阈值是5cm
		{
			hOldPen = (HPEN)SelectObject(hDc, hYellowPen);
		}
		else
		{
			hOldPen = (HPEN)SelectObject(hDc, hGreenPen);
		}
	}
	else
	{
		if (m_bBeltState)
		{
			if (m_dRightRectifyValue <= m_nRectifySetValueTwo)//阈值是5cm
			{
				hOldPen = (HPEN)SelectObject(hDc, hRedPen);
			}
			else if (m_dRightRectifyValue > m_nRectifySetValueTwo && m_dRightRectifyValue <= m_nRectifySetValue)//阈值是5cm
			{
				hOldPen = (HPEN)SelectObject(hDc, hYellowPen);
			}
			else
			{
				hOldPen = (HPEN)SelectObject(hDc, hGreenPen);
			}
		}
		else
		{
			hOldPen = (HPEN)SelectObject(hDc, hGrayPen);
		}
	}
	//画第二条线
	::MoveToEx(hDc, MulDiv(m_BeltEdgePf2.x(), clientWidth, 1920), MulDiv(m_BeltEdgePf2.y(), clientHeight, 1080), NULL);// 将绘图点移动到直线起点
	::LineTo(hDc, MulDiv(m_BeltEdgePf3.x(), clientWidth, 1920), MulDiv(m_BeltEdgePf3.y(), clientHeight, 1080));//画直线到指定的终点

	// 恢复原来的画笔
	SelectObject(hDc, hOldPen);
	// 删除创建的绿色画笔
	DeleteObject(hGreenPen);
	DeleteObject(hRedPen);
	DeleteObject(hYellowPen);
	DeleteObject(hGrayPen);

	//==========左下角画两行文字信息=========
	// 创建绿色画笔 宽度为4像素
	HPEN hGreenPen2 = CreatePen(PS_SOLID, 8, 0x00FF00);
	// 选择绿色画笔到设备环境中
	HPEN hOldPen2 = (HPEN)SelectObject(hDc, hGreenPen2);

	// 设置绿色画刷
	SetTextColor(hDc, 0x00FF00); // 设置文字颜色为绿色

	//文字显示区域
	RECT rectLeftText;
	rectLeftText.left = 10;//矩形左上角的 x 坐标
	rectLeftText.top = clientHeight - 50;//矩形左上角的 y 坐标
	rectLeftText.right = 150;//表示矩形右下角的 x 坐标
	rectLeftText.bottom = clientHeight - 30;//矩形右下角的 y 坐标
	RECT rectRightText;
	rectRightText.left = 10;//矩形左上角的 x 坐标
	rectRightText.top = clientHeight - 25;//矩形左上角的 y 坐标
	rectRightText.right = 150;//表示矩形右下角的 x 坐标
	rectRightText.bottom = clientHeight - 5;//矩形右下角的 y 坐标

	char *pLeftValue;
	char *pRightValue;
	//QString strLeftValue = QObject::tr("Left: %1 cm").arg(6.871);
	//QString strRightValue = QObject::tr("Right: %1 cm").arg(14.06);
	QString strLeftValue = A2T("左偏: %1 mm").arg(QString::number(m_dLeftRectifyValue*10,'f',1));
	QString strRightValue = A2T("右偏: %1 mm").arg(QString::number(m_dRightRectifyValue*10, 'f', 1));
	QByteArray baLeft = strLeftValue.toLocal8Bit();
	QByteArray baRight = strRightValue.toLocal8Bit();
	pLeftValue = baLeft.data();
	pRightValue = baRight.data();
	if (m_dLeftRectifyValue <= m_nRectifySetValueTwo)//阈值是5cm
	{
		SetTextColor(hDc, 0x0000FF); // 设置文字颜色为红色
	}
	else if (m_dLeftRectifyValue > m_nRectifySetValueTwo && m_dLeftRectifyValue <= m_nRectifySetValue)
	{
		SetTextColor(hDc, 0x00FFFF); // 设置文字颜色为黄色
	}
	else
	{
		SetTextColor(hDc, 0x00FF00); // 设置文字颜色为绿色
	}
	::DrawTextA(hDc, pLeftValue, strlen(pLeftValue), &rectLeftText, DT_LEFT);//左偏值
	if (m_dRightRectifyValue <= m_nRectifySetValueTwo)//阈值是5cm
	{
		SetTextColor(hDc, 0x0000FF); // 设置文字颜色为红色
	}
	else if (m_dRightRectifyValue > m_nRectifySetValueTwo && m_dRightRectifyValue <= m_nRectifySetValue)
	{
		SetTextColor(hDc, 0x00FFFF); // 设置文字颜色为黄色
	}
	else
	{
		SetTextColor(hDc, 0x00FF00); // 设置文字颜色为绿色
	}
	::DrawTextA(hDc, pRightValue, strlen(pRightValue), &rectRightText, DT_LEFT);//右偏值

	// 恢复原来的画笔
	SelectObject(hDc, hOldPen2);
	// 删除创建的绿色画笔
	DeleteObject(hGreenPen2);
}

//设置相机模式
bool CCamerSdkOper::setCameraMode(LONG lUserID, ECameraMode enModeType, QString& sErrMsg)
{
	bool bRet = false;

	DWORD dwChannel = 2;  //热成像通道
	char *m_pOutBuf = new char[ISAPI_OUT_LEN];
	memset(m_pOutBuf, 0, ISAPI_OUT_LEN);

	char *m_pStatusBuf = new char[ISAPI_STATUS_LEN];
	memset(m_pStatusBuf, 0, ISAPI_STATUS_LEN);

	//测温基本参数配置
	NET_DVR_STD_CONFIG struStdConfig = { 0 };
	struStdConfig.lpCondBuffer = &dwChannel;
	struStdConfig.dwCondSize = sizeof(dwChannel);
	struStdConfig.lpInBuffer = NULL;
	struStdConfig.dwInSize = 0;

	NET_DVR_THERMOMETRY_BASICPARAM struThermBasicParam = { 0 };
	struStdConfig.lpOutBuffer = (LPVOID)&struThermBasicParam;
	struStdConfig.dwOutSize = sizeof(struThermBasicParam);

	struStdConfig.lpStatusBuffer = m_pStatusBuf;
	struStdConfig.dwStatusSize = ISAPI_STATUS_LEN;

	DWORD dwReturned = 0;
	bRet = NET_DVR_GetSTDConfig(lUserID, NET_DVR_GET_THERMOMETRY_BASICPARAM, &struStdConfig);
	if (false == bRet)
	{
		sErrMsg = QString::fromLocal8Bit("获取测温基础参数配置失败! 错误原因：" + NET_DVR_GetLastError());
		return bRet;
	}

	//測溫模式配置
	NET_DVR_STD_CONFIG struStdConfigMode = { 0 };
	struStdConfigMode.lpCondBuffer = &dwChannel;
	struStdConfigMode.dwCondSize = sizeof(dwChannel);
	struStdConfigMode.lpInBuffer = NULL;
	struStdConfigMode.dwInSize = 0;

	NET_DVR_THERMOMETRY_MODE struMODE = { 0 };
	struStdConfigMode.lpOutBuffer = (LPVOID)&struMODE;
	struStdConfigMode.dwOutSize = sizeof(struMODE);

	struStdConfigMode.lpStatusBuffer = m_pStatusBuf;
	struStdConfigMode.dwStatusSize = ISAPI_STATUS_LEN;
	bRet = NET_DVR_GetSTDConfig(lUserID, NET_DVR_GET_THERMOMETRY_MODE, &struStdConfigMode);
	if (false == bRet)
	{
		sErrMsg = QString::fromLocal8Bit("获取测温模式配置失败! 错误原因：" + NET_DVR_GetLastError());
		return bRet;
	}

	//设置模式
	switch (enModeType)
	{
	case enNormalMode:    //普通模式
		struMODE.byMode = 0;
		break;
	case enExpertMode:    //专家模式
		struMODE.byMode = 1;
		break;
	default:
		break;
	}

	struStdConfigMode.lpInBuffer = (LPVOID)&struMODE;
	struStdConfigMode.dwInSize = sizeof(struMODE);
	bRet = NET_DVR_SetSTDConfig(lUserID, NET_DVR_SET_THERMOMETRY_MODE, &struStdConfigMode);
	if (false == bRet)
	{
		sErrMsg = QString::fromLocal8Bit("设置测温模式配置失败! 错误原因：" + NET_DVR_GetLastError());
		return bRet;
	}

	return bRet;
}

//预置点框选区域配置(框选)
bool CCamerSdkOper::setPresetArea(LONG lUserID, SPersetAreaParam sPersetData, SPersetAreaRect detectRect, QString& sErrMsg)
{
	bool bRet = false;

	DWORD dwChannel = 2;

	char *m_pStatusBuf = new char[ISAPI_STATUS_LEN];
	memset(m_pStatusBuf, 0, ISAPI_STATUS_LEN);

	//获取预置点关联测温信息
	NET_DVR_STD_CONFIG stConfig = { 0 };
	NET_DVR_THERMOMETRY_COND stCodn = { 0 };
	stCodn.dwChannel = dwChannel;
	stCodn.wPresetNo = sPersetData.wPresetNo;
	stCodn.dwSize = sizeof(stCodn);

	stConfig.lpCondBuffer = &stCodn;
	stConfig.dwCondSize = sizeof(stCodn);
	stConfig.lpInBuffer = NULL;
	stConfig.dwInSize = 0;

	NET_DVR_THERMOMETRY_PRESETINFO stPointInfo = { 0 };
	stConfig.lpOutBuffer = (LPVOID)&stPointInfo;
	stConfig.dwOutSize = sizeof(stPointInfo);

	stConfig.lpStatusBuffer = m_pStatusBuf;
	stConfig.dwStatusSize = ISAPI_STATUS_LEN;
	bRet = NET_DVR_GetSTDConfig(lUserID, NET_DVR_GET_THERMOMETRY_PRESETINFO, &stConfig);
	if (false == bRet)
	{
		sErrMsg = QString::fromLocal8Bit("获取预置点信息失败! 错误原因：" + NET_DVR_GetLastError());
		return bRet;
	}

	NET_VCA_POINT stPoint1;
	stPoint1.fX = detectRect.pointA.dPercentX;
	stPoint1.fY = detectRect.pointA.dPercentY;
	NET_VCA_POINT stPoint2;
	stPoint2.fX = detectRect.pointB.dPercentX;
	stPoint2.fY = detectRect.pointB.dPercentY;
	NET_VCA_POINT stPoint3;
	stPoint3.fX = detectRect.pointD.dPercentX;
	stPoint3.fY = detectRect.pointD.dPercentY;
	NET_VCA_POINT stPoint4;
	stPoint4.fX = detectRect.pointC.dPercentX;
	stPoint4.fY = detectRect.pointC.dPercentY;
	NET_VCA_POLYGON stPolygon;
	stPolygon.dwPointNum = 4;
	stPolygon.struPos[0] = stPoint1;
	stPolygon.struPos[1] = stPoint2;
	stPolygon.struPos[2] = stPoint4;
	stPolygon.struPos[3] = stPoint3;

	stPointInfo.struPresetInfo[0].byEnabled = 1;  //是否使能 0 - 否 1 - 是
	stPointInfo.struPresetInfo[0].byRuleCalibType = 1;  // 0-点 1-框 2-线
	stPointInfo.struPresetInfo[0].byDistanceUnit = sPersetData.byDistanceUnit;
	stPointInfo.struPresetInfo[0].wDistance = sPersetData.wDistance;
	stPointInfo.struPresetInfo[0].struRegion = stPolygon;  //区域 线（为“框”或“线”时生效）

	stConfig.lpInBuffer = (LPVOID)&stPointInfo;
	stConfig.dwInSize = sizeof(stPointInfo);
	bRet = NET_DVR_SetSTDConfig(lUserID, NET_DVR_SET_THERMOMETRY_PRESETINFO, &stConfig);
	if (false == bRet)
	{
		sErrMsg = QString::fromLocal8Bit("设置预置点信息失败! 错误原因：" + NET_DVR_GetLastError());
		return bRet;
	}

	return bRet;
}

//分析回调函数给出的pcm原始数据
void CCamerSdkOper::slotAnalyzePCMData(QByteArray szPCMData)
{
	qint32 nDb = 0;		//分贝值
	qint16 nValue = 0;	//pcm原始数据振幅
	qreal dSum = 0;		//振幅求和

	QVector<qint32> vecPCM;
	for (int i = 0; i < szPCMData.size(); i += 2)
	{
		memcpy(&nValue, szPCMData.mid(i, 2), 2);	//获取2个字节的大小（值）
		nValue = nValue * m_dDbUprate;				//对采样值进行增幅
		vecPCM.append(nValue);
		dSum += abs(nValue);	//绝对值求和
	}
	dSum = dSum / (szPCMData.size() / 2);			//求平均值（2个字节表示一个振幅，所以振幅个数为：size/2个）

	if (dSum > 0)
	{
		nDb = (qint32)(20.0 * log10(dSum));			//当前帧分贝数
		m_vecDbOrigin.push_back(nDb);						//保存当前帧分贝数，与前几帧数据求平均数以过滤掉突变数据
		if (m_vecDbOrigin.size() > m_nAvgInterval)		m_vecDbOrigin.pop_front();
		qint32 nSum = 0;
		for (qint32 i = 0; i < m_vecDbOrigin.size(); i++)
		{
			nSum += m_vecDbOrigin.at(i);
		}
		nDb = nSum / m_vecDbOrigin.size();
	}

	//间隔取分贝数
	if (m_nCount > m_nSampleInterval)
	{
		m_nDbNumOld = m_nDbNum;		//保存上一次抽取的分贝数
		m_nDbNum = nDb;				//存入新的分贝数
		m_nDbNumDiffer = m_nDbNum - m_nDbNumOld;	//求两次的差值
		//求方差
		m_vecDb.push_back(nDb);
		if (m_vecDb.size() > m_nDbDeviationNum)		m_vecDb.pop_front();

		if (m_vecDb.size() > 0)
		{
			//求平均值
			qreal dSum = 0.00;
			for (qint32 i = 0; i < m_vecDb.size(); i++)
			{
				dSum += m_vecDb.at(i);
			}
			qreal dAvg = dSum / m_vecDb.size();
			//计算方差
			qreal dSumDeviation = 0.00;
			for (qint32 i = 0; i < m_vecDb.size(); i++)
			{
				dSumDeviation += (m_vecDb.at(i) - dAvg) * (m_vecDb.at(i) - dAvg);
			}
			m_dDbDeviation = dSumDeviation / m_vecDb.size();
		}

		//emit sigGetDbNum(m_nDbNum, m_nDbNumDiffer, m_dDbDeviation);
		m_dValue = static_cast<double>(m_nDbNum);
		m_pDevDataCam->m_dAtcDecibel = m_dValue;

		m_nCount = 0;
	}
	else
	{
		m_nCount++;
	}
}

bool CCamerSdkOper::recordVideo(QString & sPath, int nDevId, QString &sReInfo)
{
	SCamerInfo cCamerInfo = m_pDevDataCam->m_cMapCamerInfo[nDevId];
	QString sDevName = "";
	if (nDevId == enIR)
	{
		sDevName = A2T("红外相机");
	}
	else if (nDevId == enCamer)
	{
		sDevName = A2T("图像相机");
	}
	else
	{

	}
	//1.如果没开启预览 先开启预览
	if (!cCamerInfo.m_bConStatus)
	{
		//2.如果预览开启失败 返回false
		if (!realPlay(nDevId, sReInfo))
		{
			return false;
		}
		cCamerInfo = m_pDevDataCam->m_cMapCamerInfo[nDevId];
	}
	//3.如果正在录像 方法true
	if (cCamerInfo.m_bIsRecording)
	{
		sReInfo += A2T("%1正在录像").arg(sDevName);
		return true;
	}

	QString sFoldPath = sPath + QDateTime::currentDateTime().toString("yyyyMM") + "/" + QDateTime::currentDateTime().toString("dd") + "/";
	QDir folder(sFoldPath);
	if (!folder.exists())
	{
		if (folder.mkpath("."))
		{

		}
	}

	QString sVideoPath = sFoldPath + QDateTime::currentDateTime().toString("yyyy-MM-dd-hh-mm-ss") + ".mp4";
	sPath = sVideoPath;
	char *cRecName;
	QByteArray ba = sVideoPath.toLatin1();
	cRecName = ba.data();
	//4.开启录像成功
	if (NET_DVR_SaveRealData(cCamerInfo.m_lHandle, cRecName))
	{
		sReInfo += A2T("%1开启录像。").arg(sDevName);
		cCamerInfo.m_bIsRecording = true;
		m_pDevDataCam->m_cMapCamerInfo[nDevId] = cCamerInfo;
		return true;
	}
	//5.开启录像失败
	else
	{
		sReInfo += A2T("%1开启录像失败，").arg(sDevName) + getErrMsg();
		cCamerInfo.m_bIsRecording = false;
		m_pDevDataCam->m_cMapCamerInfo[nDevId] = cCamerInfo;
		return false;
	}
}

bool CCamerSdkOper::recordVideo(QString & sPath, HWND hHand, QString &sReInfo)
{
	if (!m_pDevDataCam->m_cMapHandInfo.contains(hHand))
	{
		sReInfo += A2T("未开启预览，请先开启预览。");
		return false;
	}
	SCamerInfo cCamerInfo = m_pDevDataCam->m_cMapHandInfo[hHand];    //相机状态数组
	if (cCamerInfo.m_bIsRecording)
	{
		sReInfo += A2T("正在录像");
		return true;
	}

	QString sFoldPath = sPath + QDateTime::currentDateTime().toString("yyyyMM") + "/" + QDateTime::currentDateTime().toString("dd") + "/";
	QDir folder(sFoldPath);
	if (!folder.exists())
	{
		if (folder.mkpath("."))
		{

		}
	}

	QString sVideoPath = sFoldPath + QDateTime::currentDateTime().toString("yyyy-MM-dd-hh-mm-ss") + ".mp4";

	char *cRecName;
	QByteArray ba = sVideoPath.toLatin1();
	cRecName = ba.data();
	if (NET_DVR_SaveRealData(cCamerInfo.m_lHandle, cRecName))
	{
		sReInfo += A2T("开启录像。");
		cCamerInfo.m_bIsRecording = true;
		m_pDevDataCam->m_cMapHandInfo[hHand] = cCamerInfo;
		return true;
	}
	else
	{
		sReInfo += A2T("开启录像失败，") + getErrMsg();
		cCamerInfo.m_bIsRecording = false;
		m_pDevDataCam->m_cMapHandInfo[hHand] = cCamerInfo;
		return false;
	}
}

bool CCamerSdkOper::stopRecordVideo(int nDevId, QString &sReInfo)
{
	SCamerInfo cCamerInfo = m_pDevDataCam->m_cMapCamerInfo[nDevId];
	//1.如果视频没有开启预览  表示没开启录像
	if (!cCamerInfo.m_bConStatus)
	{
		sReInfo += A2T("未开启预览和录像。");
		return true;
	}
	if (!cCamerInfo.m_bIsRecording)
	{
		sReInfo += A2T("未开启录像。");
		return true;
	}
	if (NET_DVR_StopSaveRealData(cCamerInfo.m_lHandle))
	{
		sReInfo += A2T("停止录像。");
		cCamerInfo.m_bIsRecording = false;
		m_pDevDataCam->m_cMapCamerInfo[nDevId] = cCamerInfo;
		return true;
	}
	else
	{
		sReInfo += A2T("停止录像失败，") + getErrMsg();
		return false;
	}
}

bool CCamerSdkOper::stopRecordVideo(HWND hHand, QString &sReInfo)
{
	//如果没数组 表示 为开启预览  没开启预览 表示没开启录像
	if (!m_pDevDataCam->m_cMapHandInfo.contains(hHand))
	{
		sReInfo += A2T("未开启预览和录像。");
		return true;
	}
	SCamerInfo cCamerInfo = m_pDevDataCam->m_cMapHandInfo[hHand];    //相机状态数组
	if (!cCamerInfo.m_bIsRecording)
	{
		sReInfo += A2T("未开启录像。");
		return true;
	}
	if (NET_DVR_StopSaveRealData(cCamerInfo.m_lHandle))
	{
		sReInfo += A2T("停止录像。");
		cCamerInfo.m_bIsRecording = false;
		m_pDevDataCam->m_cMapHandInfo[hHand] = cCamerInfo;
		return true;
	}
	else
	{
		sReInfo += A2T("停止录像失败，") + getErrMsg();
		return false;
	}
}

bool CCamerSdkOper::startVoiceTalk(int nDevId, QString &sReInfo)
{
	if (!initAndLogin(sReInfo))
	{
		return false;
	}
	LONG lLoginID = m_pDevDataCam->m_sStruDeviceInfo.lLoginID;
	SCamerInfo cCamerInfo = m_pDevDataCam->m_cMapCamerInfo[nDevId];
	//1.如果语音已经连接 返回true
	if (cCamerInfo.m_bConStatus)
	{
		sReInfo += A2T("已经开启语音对讲。");
		m_pDevDataCam->m_bIsOpenTalkBack = true;
		return true;
	}
	cCamerInfo.m_cClientInfo.lLinkMode = 0;
	cCamerInfo.m_cClientInfo.sMultiCastIP = NULL;
	qint32 nCurChan = 1;
	qint32 nNeedEncode = 1;
	//cCamerInfo.m_lHandle = NET_DVR_StartVoiceCom_V30(lLoginID, 1, 0, fVoiceTalkDataCallBack, (void*)this);
	//打开语音对讲 入参1:连接时注册的登录ID | 入参2:接受语音信号的通道号 | 入参3:是否需要对信号进行解码 0解码为G722 1原始PCM数据 |
	//入参4:接受语音数据回调函数 | 入参5: 类指针，便于将接受的数据回传入本类中
	cCamerInfo.m_lVoiceHandle = NET_DVR_StartVoiceCom_V30(lLoginID, nCurChan, nNeedEncode, fVoiceTalkDataCallBack, (void*)this);
	if (-1 == cCamerInfo.m_lVoiceHandle)
	{
		sReInfo += A2T("开启语音对讲失败，") + getErrMsg();
		cCamerInfo.m_bConStatus = false;
		m_pDevDataCam->m_bIsOpenTalkBack = false;
		m_pDevDataCam->m_cMapCamerInfo[nDevId] = cCamerInfo;
		return false;
	}
	else
	{
		sReInfo += A2T("开启语音对讲。");
		cCamerInfo.m_bConStatus = true;
		m_pDevDataCam->m_bIsOpenTalkBack = true;
		m_pDevDataCam->m_cMapCamerInfo[nDevId] = cCamerInfo;
		return true;
	}
}

bool CCamerSdkOper::stopVoiceTalk(int nDevId, QString &sReInfo)
{
	SCamerInfo cCamerInfo = m_pDevDataCam->m_cMapCamerInfo[nDevId];
	//1.如果未连接或者连接失败 返回true
	if (cCamerInfo.m_bConStatus == false)
	{
		sReInfo += A2T("未开启语音对讲。");
		return true;
	}
	//2.停止对讲
	if (NET_DVR_StopVoiceCom(cCamerInfo.m_lVoiceHandle))
	{
		sReInfo += A2T("关闭语音对讲。");
		cCamerInfo.resetData();
		m_pDevDataCam->m_cMapCamerInfo[nDevId] = cCamerInfo;
		m_pDevDataCam->m_bIsOpenTalkBack = false;
		return true;
	}
	else
	{
		sReInfo += A2T("关闭语音对讲失败，") + getErrMsg();
		cCamerInfo.resetData();
		m_pDevDataCam->m_cMapCamerInfo[nDevId] = cCamerInfo;
		return false;
	}
}

bool CCamerSdkOper::startVoiceForward(int nDevId, QString &sReinfo)
{
	if (!initAndLogin(sReinfo))
	{
		return false;
	}
	LONG lLoginID = m_pDevDataCam->m_sStruDeviceInfo.lLoginID;
	SCamerInfo cCamerInfo = m_pDevDataCam->m_cMapCamerInfo[nDevId];
	//语音转发
	cCamerInfo.m_lVoiceForwardHandle = NET_DVR_StartVoiceCom_MR_V30(lLoginID, 1, fVoiceTransPCMDataCallBack, NULL);
	if (cCamerInfo.m_lVoiceForwardHandle < 0)
	{
		sReinfo=A2T("打开语音转发失败")+getErrMsg();
		return false;
	}
	else
	{
		sReinfo = A2T("打开语音转发成功").arg(NET_DVR_GetLastError());
		return true;
	}

}

bool CCamerSdkOper::endVoiceForward(int nDevId, QString &sReinfo)
{
	SCamerInfo cCamerInfo = m_pDevDataCam->m_cMapCamerInfo[nDevId];
	//停止对讲
	if (NET_DVR_StopVoiceCom(cCamerInfo.m_lVoiceForwardHandle))
	{
		sReinfo += A2T("关闭语音转发。");
		cCamerInfo.resetData();
		m_pDevDataCam->m_cMapCamerInfo[nDevId] = cCamerInfo;
		return true;
	}
	else
	{
		sReinfo += A2T("关闭语音转发，") + getErrMsg();
		cCamerInfo.resetData();
		m_pDevDataCam->m_cMapCamerInfo[nDevId] = cCamerInfo;
		return false;
	}
}

bool CCamerSdkOper::broadcastAudio(int nDevId, QString &sReInfo)
{
	if (!initAndLogin(sReInfo))
	{
		return false;
	}
	LONG lLoginID = m_pDevDataCam->m_sStruDeviceInfo.lLoginID;
	LONG lVoiceTransHanle = NET_DVR_StartVoiceCom_MR_V30(lLoginID, 1, fVoiceTransPCMDataCallBack, NULL);
	if (lVoiceTransHanle < 0)
	{
		sReInfo = A2T("打开声音转发失败,错误原因%1").arg(getErrMsg());
		return false;
	}

	//语音转发
	QString sPath= QCoreApplication::applicationDirPath()+"/broadcast.pcm";
	FILE* m_hStreamFile = fopen(sPath.toLocal8Bit(), "rb+");
	if (NULL == m_hStreamFile)
	{
		sReInfo = A2T("打开音频文件失败,路径:%1").arg(sPath);
		return false;
	}
	BYTE pBuf[1920];
	BOOL bBufFull = FALSE;
	DWORD dwSize = 1920;
	DWORD dwDataLen = 0;
	while (1)
	{
		if (!bBufFull)
		{
			memset(pBuf, 0, dwSize); // 清空缓冲区
			//每次读取640字节
			dwDataLen = fread(pBuf, 1, dwSize, m_hStreamFile);
			if (dwDataLen == 0)
			{
				break;
			}
			else
			{
				if (pBuf != NULL)
				{
					bool bRet = NET_DVR_VoiceComSendData(lVoiceTransHanle, (char*)pBuf, 1920);
					if (!bRet)
					{
						sReInfo = A2T("播放音频失败,错误原因%1").arg(getErrMsg());
						return false;
					}
				}
				sysSleepTime(40);
			}
		}
		else
		{
			break;
		}
	}

	if (m_hStreamFile != NULL)
	{
		fclose(m_hStreamFile);
	}

	if (!NET_DVR_StopVoiceCom(lVoiceTransHanle))
	{
		sReInfo = A2T("关闭语音转发失败,错误原因%1").arg(getErrMsg());
		return false;
	}

	sReInfo = A2T("发送音频成功");
	return true;
}

